package Exercises;

import utils.MUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import static utils.MUtils.print;

/**
 * Instruction：基于Lock和Condition的生产者与消费者模型
 * Author：@author MaLi
 */
public class Exercise02 {

    private static class DataBuffer {
        private List<String> container = new ArrayList<>(10);
        private int MAXSIZE = 10;
        private AtomicInteger size = new AtomicInteger(0);
        private Lock lock = new ReentrantLock();
        private Condition notFullCondition = lock.newCondition();
        private Condition notEmptyCondition = lock.newCondition();

        //向缓冲区放入元素
        public void add(String element) {
            lock.lock();
            try {
                //已经满了
                if (size.get() >= MAXSIZE) {
                    try {
                        notFullCondition.await();//阻塞生产者
                        print("缓冲区已经满了, 请尽快消费...");
                        MUtils.timeDelay(1);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                } else {
                    //未满
                    container.add(element);
                    size.incrementAndGet();
                    notEmptyCondition.signalAll(); //通知消费者开始消费
                    print(Thread.currentThread().getName() + " -->生产了元素: " + element);
                    MUtils.timeDelay(1);
                }
            } finally {
                lock.unlock();
            }
        }

        //在缓冲区获取元素
        public String get() {
            String element = null;
            lock.lock();

            try {
                if (size.get() <= 0) {
                    try {
                        notEmptyCondition.await();
                        print("缓冲区已经空了, 请继续生产...");
                        MUtils.timeDelay(3);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                } else {
                    element = container.remove(0);
                    size.decrementAndGet();
                    notFullCondition.signalAll();
                    print(Thread.currentThread().getName() + " -->消费了元素: " + element);
                    MUtils.timeDelay(3);
                }
            } finally {
                lock.unlock();
            }
            return element;
        }
    }

    public static void main(String[] args) {
        AtomicInteger num = new AtomicInteger(0);
        DataBuffer dataBuffer = new DataBuffer();
        ArrayList<Thread> threads = new ArrayList<>();
        CountDownLatch countDownLatch = new CountDownLatch(1);
        //创建3个生产者
        for (int i = 0; i < 3; i++) {
            Thread thread = new Thread(() -> {
                while (true) {
                    dataBuffer.add("element --" + num.incrementAndGet());
                }
            }, "ProducerThread-" + i);
            threads.add(thread);
        }

        //创建5个消费者
        for (int i = 0; i < 5; i++) {
            Thread thread = new Thread(() -> {
                while (true) {
                    dataBuffer.get();
                }
            }, "ConsumerThread-" + i);
            threads.add(thread);
        }

        for (Thread thread : threads) {
            thread.start();
        }

        //主线程暂停在这里
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}
